var x = 0

var foo = {
  x: 1,
  bar: {
    x: 2,
    baz: function () {
      console.log(this.x)
    }
  }
}

var a = foo.bar.baz

foo.bar.baz() // 2
a() // 0 , this指向window

/*
this 永远指向函数运行时所在的对象，而不是函数创建时所在的对象
匿名函数和不处于任何对象中的函数，This指向window
call, apply, with指的This是谁就是谁。
普通函数调用，函数被谁调用，This就指向谁
*/


var x = 0
var foo = {
  x: 1,
  bar: function () {
    console.log(this.x);
    var that = this;
    return function () {
      console.log(this.x)
      console.log(that.x)
    }
  }
}

foo.bar() // 1
foo.bar()() // 1 0 1
// 上面的例子中 bar 里面返回了一个匿名函数，这个匿名函数可以在外部被调用即：foo.bar()() 读取到了bar的执行上下文的变量对象 that，这个函数就形成了一个闭包。

var x = 0
var bar = function () {
  var n = 999
  return function () {
    return n;
  }
}

var outer = bar()
outer() // 999
// 读取函数内部的变量
// 让这些变量的值始终保持在内存中

var add
var bar = function () {
  var n = 999
  add = function () {
    n += 1
  };
  return function () {
    return n
  }
}

var outer = bar()

outer() // 999
add ()
outer() // 1000

// 会导致内存泄漏，慎用
// 闭包会修改内部变量的值，所以在使用闭包作为对象的公用方法时要谨慎。
// 闭包的一个应用，单例模式


// 单例：
var singleton = function (fn) {
  var result;
  return function () {
    return result || (result.fn.apply(this, arguments));
  }
}

// 另一种形式
var singleton = (function () {
  var instance;
  return function (object) {
    if (!instance) {
      instance = new Object()
    }
    return instance;
  }
})();
